using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel.Mappings.Enums;
using Microsoft.Practices.RepositoryFactory.SchemaDiscovery.ObjectModel.Base;
using System.Globalization;
using Microsoft.Practices.RecipeFramework.Extensions.CommonHelpers;
using Resources=Microsoft.Practices.RepositoryFactory.Properties.Resources;

namespace Microsoft.Practices.RepositoryFactory.CodeGeneration.ObjectModel.NamingConventions
{
    /// <summary/>
    public static class NamingHelper
    {
        /// <summary>
        /// Defaults to SqlServer naming strategy.
        /// </summary>
        private static NamingStrategy _namingStrategy = new SqlServerNamingStrategy();

        #region Public Implementation
        public static NamingStrategy NamingStrategy
        {
            get { return _namingStrategy; }
        }
        
        public static void SetNamingStrategy(String dbProviderName)
        {
            _namingStrategy = NamingStrategyFactory.Create(dbProviderName);
        }
        
        
        /// <summary>
        /// Gets the name of the SP.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="spType">Type of the sp.</param>
        /// <returns></returns>
        public static string GetSPName(Table table, StoredProcedureType spType)
        {
            switch(spType)
            {
                case StoredProcedureType.Insert:
                    return GetInsertSPName(GetTableName(table));
                case StoredProcedureType.Delete:
                    return GetDeleteSPName(GetTableName(table));
                case StoredProcedureType.Update:
                    return GetUpdateSPName(GetTableName(table));
                case StoredProcedureType.GetByPK:
                    return GetGetByPKSPName(table);
                case StoredProcedureType.GetByFK:
                    return GetGetByFKSPName(table);
                case StoredProcedureType.GetAll:
                    return GetGetAllSPName(GetTableName(table));
                default:
                    return "";
            }
        }

        /// <summary>
        /// Gets the name of the SP.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="spType">Type of the sp.</param>
        /// <returns></returns>
        public static string GetSPName(string table, StoredProcedureType spType)
        {
            switch(spType)
            {
                case StoredProcedureType.Insert:
                    return GetInsertSPName(table);
                case StoredProcedureType.Delete:
                    return GetDeleteSPName(table);
                case StoredProcedureType.Update:
                    return GetUpdateSPName(table);
                case StoredProcedureType.GetAll:
                    return GetGetAllSPName(table);
                default:
                    return "";
            }
        }

        /// <summary>
        /// Cleans the name of the input parameter.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <returns></returns>
        public static string GetFieldName(string type)
        {
            return _namingStrategy.GetFieldName(type);
        }

        /// <summary>
        /// Gets the name of the variable.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public static string GetVariableName(string type)
        {
            return GetVariableName(type, false);
        }

        /// <summary>
        /// Gets the name of the variable.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public static string GetVariableName(string type, bool convertToValidIdentifier)
        {
            return _namingStrategy.GetVariableName(type, convertToValidIdentifier);
        }


        /// <summary>
        /// Gets the name of the property.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public static string GetPropertyName(string type)
        {
            return _namingStrategy.GetPropertyName(type);
        }

        /// <summary>
        /// Gets the name of the db variable.
        /// </summary>
        /// <param name="dbObject">The db object.</param>
        /// <returns></returns>
        public static string GetDbVariableName(string dbObject)
        {
            string response = string.Empty;

            if(!string.IsNullOrEmpty(dbObject))
            {
                //response = GetDbObjectPrefix() + ReplaceDbIllegalCharacters(dbObject);
                response = GetVariableName(dbObject);
                response = ReplaceDbIllegalCharacters(response);
            }

            return response;
        }

        public static string GetMapBetweenPropertyAndDbVariable(string dbObject)
        {
            string response = string.Empty;

            if(!string.IsNullOrEmpty(dbObject))
            {
                response = NamingHelper.CleanInputParameterName(dbObject);
                response = response.Substring(0, 1).ToUpper() + response.Substring(1);
            }

            return response;
        }

        public static string GetMethodParameterName(string type)
        {
            return _namingStrategy.GetMethodParameterName(type);
        }

        /// <summary>
        /// Replaces the db illegal characters.
        /// </summary>
        /// <param name="dbObject">The db object.</param>
        /// <returns></returns>
        public static string ReplaceDbIllegalCharacters(string dbObject)
        {
            string response = string.Empty;

            if(!string.IsNullOrEmpty(dbObject))
            {
                response = dbObject.Replace("@", string.Empty);
                response = response.Replace(" ", string.Empty);
                response = response.Replace("[", string.Empty);
                response = response.Replace("]", string.Empty);
            }

            if (response.Contains("."))
            {
               int startPosition = response.LastIndexOf(".") + 1;
               response = response.Substring(startPosition);
            }

            return response;
        }

        /// <summary>
        /// Cleans the name of the input parameter.
        /// </summary>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <returns></returns>
        public static string CleanInputParameterName(string parameterName)
        {
            string response = string.Empty;

            if(!string.IsNullOrEmpty(parameterName))
            {
                response = parameterName.Replace(GetDbObjectPrefix(), string.Empty);
            }

            return response;
        }

        /// <summary>
        /// Gets the name of the operation.
        /// </summary>
        /// <param name="operationName">Name of the operation.</param>
        /// <returns></returns>
        public static string GetOperationName(string operationName)
        {
            string response = string.Empty;

            if(!string.IsNullOrEmpty(operationName))
            {
                response = operationName.Replace(" ", string.Empty);
            }

            return response;
        }
        #endregion

        #region Private Implementation

        private static string GetInsertSPName(string table)
        {
            if(!string.IsNullOrEmpty(table))
            {
                return "Insert" + table.Replace(" ", string.Empty);
            }
            else
            {
                return "Insert";
            }
        }

        private static string GetDeleteSPName(string table)
        {
            if(!string.IsNullOrEmpty(table))
            {
                return "Delete" + table.Replace(" ", string.Empty);
            }
            else
            {
                return "Delete";
            }
        }

        private static string GetUpdateSPName(string table)
        {
            if(!string.IsNullOrEmpty(table))
            {
                return "Update" + table.Replace(" ", string.Empty);
            }
            else
            {
                return "Update";
            }
        }

        private static string GetGetAllSPName(string table)
        {
            if(!string.IsNullOrEmpty(table))
            {
                return "GetAllFrom" + table.Replace(" ", string.Empty);
            }
            else
            {
                return "GetAllFrom";
            }
        }

        private static string GetGetByPKSPName(Table table)
        {
            string response = string.Empty;

            if(table != null)
            {
                response = string.Format(CultureInfo.CurrentCulture, Resources.GetWithArgument, GetTableName(table).Replace(" ", string.Empty));

                foreach(Column column in table.Columns)
                {
                    if(column.IsPrimaryKey)
                    {
                        response += string.Format(CultureInfo.CurrentCulture, Resources.ByAndWithArgument, column.Name);
                    }
                }

                if(response.Length > 0)
                {
                    response = response.Substring(0, response.Length - 3);
                }
            }

            //SP Names need to be less than 128 characters
            if(response.Length > 128)
            {
                response = "GetByPK";
            }

            return response;
        }

        private static string GetGetByFKSPName(Table table)
        {
            string response = String.Empty;

            if(table != null)
            {
                response = string.Format(CultureInfo.CurrentCulture, Resources.GetWithArgument, GetTableName(table).Replace(" ", string.Empty));

                foreach(Column column in table.Columns)
                {
                    if(column.IsForeignKey)
                    {
                        response += string.Format(CultureInfo.CurrentCulture, Resources.ByAndWithArgument, column.Name);
                    }
                }

                if(response.Length > 0)
                {
                    response = response.Substring(0, response.Length - 3);
                }
            }

            //SP Names need to be less than 128 characters
            if(response.Length > 128)
            {
                response = "GetByFK";
            }

            return response;
        }

        private static string GetTableName(Table table)
        {
            const string DBO_SCHEMA = "dbo";

            if(string.Compare(table.Schema, DBO_SCHEMA, StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                return table.Name;
            }
            else
            {
                return table.Schema + table.Name;
            }
        }

        private static string GetDbObjectPrefix()
        {
            return "_";
        }

        #endregion
    }
}